/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lvyh.lightframe.cloud.gateway.filter;

import cn.hutool.core.util.StrUtil;
import com.lvyh.lightframe.cloud.common.constant.SystemConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import sun.misc.BASE64Decoder;

import java.net.URI;

/**
 * @author lvyh 2021/10/08.
 */
@Component
public class AddParamFilter implements GlobalFilter, Ordered {
    private static final Logger logger = LoggerFactory.getLogger(AddParamFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        StringBuilder query = new StringBuilder();
        URI uri = exchange.getRequest().getURI();

        String token = exchange.getRequest().getHeaders().getFirst(SystemConstants.AUTHORIZATION_KEY);
        if (!StrUtil.isBlank(token) && token.startsWith(SystemConstants.BASIC_PREFIX)) {
            token = token.replace(SystemConstants.BASIC_PREFIX, "");
            String decodedAuth = getFromBASE64(token);
            String[] arr = decodedAuth.split(":");
            logger.info("basic authorization decoded from base64:{}", decodedAuth);

            query.append("client_id=").append(arr[0]).append('&');
            query.append("client_secret=").append(arr[1]).append('&');
        }

        String originalQuery = uri.getRawQuery();
        if (StringUtils.hasText(originalQuery)) {
            if (!query.toString().contains("&")) {
                query.append('&');
            }
            query.append(originalQuery);
            if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
                query.append('&');
            }
        }
        String bodyString = (String) exchange.getAttributes().get(SystemConstants.FORM_PARAM);
        if (bodyString != null) {
            if (!query.toString().contains("&")) {
                query.append('&');
            }
            query.append(bodyString);
        }

        logger.info("print add param url:{}", query.toString());
        try {
            URI newUri = UriComponentsBuilder.fromUri(uri).replaceQuery(query.toString()).build(true).toUri();
            ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build();
            return chain.filter(exchange.mutate().request(request).build());
        } catch (RuntimeException ex) {
            throw new IllegalStateException("Invalid URI query: " + query.toString() + "");
        }
    }


    private String getFromBASE64(String s) {
        if (s == null)
            return null;
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            byte[] b = decoder.decodeBuffer(s);
            return new String(b);
        } catch (Exception e) {
            return null;
        }
    }


    @Override
    public int getOrder() {
        return -100;
    }

}
